#include "FileClear.h"
#include "../log/SysLog.h"
#include "../service/AlarmService.h"
#include "../util/FileUtil.h"
#include "../util/HttpUtil.h"
#include "../util/Base64Util.h"
#include "../util/JsonUtil.h"
#include "../util/TextUtil.h"
#include "../config/SystemConfig.h"

FileClear::FileClear()
	: m_run(true)
{
}

FileClear::~FileClear()
{
}

void FileClear::Start()
{
	// 设置运行标志
	m_run = true;

	// 数据清理线程
	m_clear_thread = std::thread([&]() {
		while (m_run)
		{
			// 获取清理设备
			std::vector<std::string> devices;
			{
				std::unique_lock<std::mutex> _guard(m_device_lock);
				while (!m_devices.empty())
				{
					std::string device = m_devices.front();
					m_devices.pop();
					devices.push_back(device);
				}
			}

			// 清理设备资源
			for (size_t index = 0; index < devices.size(); ++index)
			{
				LOG_INFO("begin to clear device {} alarm.", devices[index]);
				// 清理设备报警
				ClearDeviceAlarm(devices[index]);
				// 清理设备目录
				if (!FileUtil::RemoveDirs(FileUtil::GetAppPath(devices[index])))
				{
					std::unique_lock<std::mutex> _guard(m_device_lock);
					m_devices.push(devices[index]);
				}
			}

			// 清理临时文件
			std::vector<std::string> files;
			{
				std::unique_lock<std::mutex> _guard(m_file_lock);
				while (!m_files.empty())
				{
					std::string file = m_files.front();
					m_files.pop();
					files.push_back(file);
				}
			}
			for (size_t index = 0; index < files.size(); ++index)
			{
				FileUtil::RemoveFile(files[index]);
			}

			// 休息片刻重试
			bool exit = false;
			for (int index = 0; index < 10; ++index)
			{
				if (!m_run)
				{
					exit = true;
					break;
				}
				std::this_thread::sleep_for(std::chrono::seconds(1));
			}
			if (exit)
			{
				break;
			}
		}
	});

	// 数据上传线程
	m_upload_thread = std::thread([&]() {
		AlarmService alarmService;
		while (m_run)
		{
			// 报警上传地址
			std::string url = SystemConfig::get_mutable_instance().GetBoxConf().GetAlarmUrl();
			if (url.empty())
			{
				std::this_thread::sleep_for(std::chrono::seconds(1));
				continue;
			}

			// 上传报警记录
			std::string alarm_url = url + "/alarm";
			UploadAlarm(alarm_url);

			// 上传录像信息
			std::string record_url = url + "/alarmRecord";
			UploadRecord(record_url);

			// 休息片刻
			bool exit = false;
			for (int index = 0; index < 2; ++index)
			{
				if (!m_run)
				{
					exit = true;
					break;
				}
				std::this_thread::sleep_for(std::chrono::seconds(1));
			}
			if (exit)
			{
				break;
			}
		}
	});
}

void FileClear::Stop()
{
	m_run = false;
	if (m_clear_thread.joinable())
	{
		m_clear_thread.join();
	}
	if (m_upload_thread.joinable())
	{
		m_upload_thread.join();
	}
}

void FileClear::AddDevice(std::string deviceId)
{
	std::unique_lock<std::mutex> _guard(m_device_lock);
	m_devices.push(deviceId);
}

void FileClear::AddFile(std::string filePath)
{
	std::unique_lock<std::mutex> _guard(m_file_lock);
	m_files.push(filePath);
}

void FileClear::ClearDeviceAlarm(std::string device)
{
	AlarmService alarmService;
	while (true)
	{
		std::vector<AlarmInfo> alarms;
		alarmService.FindByDevice(0, 30, device, alarms);
		if (alarms.size() <= 0)
		{
			break;
		}

		for (size_t index = 0; index < alarms.size(); ++index)
		{
			if (!alarms[index].GetImagePath().empty())
			{
				AddFile(alarms[index].GetImagePath());
			}
			if (!alarms[index].GetRecordPath().empty())
			{
				AddFile(alarms[index].GetRecordPath());
			}
			alarmService.Delete(alarms[index]);
		}

		std::this_thread::sleep_for(std::chrono::seconds(1));
	}
}

void FileClear::ClearExpiredAlarm()
{
	int expred_day = SystemConfig::get_mutable_instance().GetBoxConf().GetSaveDays();
	DateTime current_time = DateTime::Now();
	current_time.AddSeconds(-(expred_day * 24 * 3600));

	AlarmService alarmService;
	while (true)
	{
		std::vector<AlarmInfo> alarms;
		alarmService.FindPast(0, 30, current_time.ToNormalString(), alarms);
		if (alarms.size() <= 0)
		{
			break;
		}

		for (size_t index = 0; index < alarms.size(); ++index)
		{
			if (!alarms[index].GetImagePath().empty())
			{
				AddFile(alarms[index].GetImagePath());
			}
			if (!alarms[index].GetRecordPath().empty())
			{
				AddFile(alarms[index].GetRecordPath());
			}
			alarmService.Delete(alarms[index]);
		}

		std::this_thread::sleep_for(std::chrono::seconds(1));
	}
}

void FileClear::UploadAlarm(std::string url)
{
	AlarmService alarmService;

	// 查询记录
	std::vector<AlarmInfo> alarms;
	alarmService.FindLatest(0, 30, alarms);
	if (alarms.size() <= 0)
	{
		return;
	}

	// 上传记录
	for (int index = 0; index < alarms.size(); ++index)
	{
		AlarmInfo item = alarms[index];
		std::string dist_url = boost::str(boost::format("%s?boxId=%s")
			% url % SystemConfig::get_mutable_instance().GetBoxConf().GetId());
		try
		{
			boost::property_tree::ptree pt;
			pt.put("id", item.GetId());
			pt.put("deviceId", item.GetDeviceId());
			pt.put("deviceName", item.GetDeviceName());
			pt.put("alarmType", item.GetAlarmType());
			pt.put("alarmInfo", item.GetAlarmInfo());
			std::string content = FileUtil::Read(item.GetImagePath());
			if (!content.empty())
			{
				pt.put("pic", Base64Util::Encode(content, content.length()));
			}
			pt.put("alarmTime", item.GetAlarmTime().ToNormalString());

			std::stringstream stream;
			boost::property_tree::write_json(stream, pt);
			std::string json = stream.str();

			std::string body;
			if (!HttpUtil::DoPost(dist_url, json, body))
			{
				LOG_WARN("upload alarm {} error.", json);
				continue;
			}

			JsonUtil jsonUtil;
			if (!jsonUtil.Parse(body))
			{
				LOG_WARN("parse alarm upload result error: {}", body);
				continue;
			}

			int error = jsonUtil.GetInt("error", -1);
			std::string msg = jsonUtil.GetString("description", "");
			if (jsonUtil.GetInt("error", -1) != 0)
			{
				LOG_WARN("upload alarm error: {}:{}", error, TextUtil::get_mutable_instance().Utf82Ascii(msg));
				continue;
			}

			alarmService.Upload(item);
		}
		catch (boost::property_tree::ptree_error pt)
		{
			LOG_ERROR("upload alarm exception: {}", pt.what());
		}
	}
}

void FileClear::UploadRecord(std::string url)
{
	AlarmService alarmService;

	// 查询记录
	std::vector<AlarmInfo> alarms;
	alarmService.FindAlarmRecord(0, 30, alarms);
	if (alarms.size() <= 0)
	{
		return;
	}

	// 上传记录
	for (int index = 0; index < alarms.size(); ++index)
	{
		AlarmInfo item = alarms[index];
		std::string dist_url = boost::str(boost::format("%s?boxId=%s&deviceId=%s&alarmId=")
			% url % SystemConfig::get_mutable_instance().GetBoxConf().GetId() % item.GetDeviceId() % item.GetId());
		try
		{
			if (!FileUtil::Exists(item.GetRecordPath()))
			{
				alarmService.Delete(item);
				continue;
			}

			std::string body;
			if (!HttpUtil::Upload(dist_url, item.GetRecordPath(), body))
			{
				LOG_WARN("upload alarm record {} error.", item.GetId());
				continue;
			}

			JsonUtil jsonUtil;
			if (!jsonUtil.Parse(body))
			{
				LOG_WARN("parse alarm record upload result error: {}", body);
				continue;
			}

			int error = jsonUtil.GetInt("error", -1);
			std::string msg = jsonUtil.GetString("description", "");
			if (jsonUtil.GetInt("error", -1) != 0)
			{
				LOG_WARN("upload alarm record error: {}:{}", error, TextUtil::get_mutable_instance().Utf82Ascii(msg));
				continue;
			}

			alarmService.Upload(item);
		}
		catch (boost::property_tree::ptree_error pt)
		{
			LOG_ERROR("upload alarm record exception: {}", pt.what());
		}
	}
}